/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdeditg
 * FILE:		sdeditg shellinst.cpp
 * PURPOSE:		SD Edit shell handler installaion/uninstallation
 */

namespace Shellinst
{

enum Loc
{
	LocUser,
	LocComputer
};

SDE_ENUM_VAL LocEnumVals[] = 
{
	{L"USER", LocUser},
	{L"COMPUTER", LocComputer}
};

SDE_ENUM LocEnum = 
{
	RTL_NUMBER_OF(LocEnumVals),
	LocUser,
	LocEnumVals
};

enum OptionIndex //synch with Options
{
	OiLocation,
	OiInstall,
	OiUninstall,
	OiVerbName
};

SDE_OPT StaticShiOptions[] = 
{
	{L"LOCATION", SDE_OPT_SET, SptEnum, &LocEnum},
	{L"INSTALL", 0, SptPresent},
	{L"UNINSTALL", 0, SptPresent},
	{L"VERBNAME", SDE_OPT_SET, SptString, L"Invoke SD Edit"}
};

SDE_OPTS StaticShiOpts =
{
	RTL_NUMBER_OF(StaticShiOptions),
	StaticShiOptions
};

class ShellinstModule : public Module::ModuleObject
{
	auto_SDE_OPTS ModOpts;

public:
	ShellinstModule() :
		ModOpts(StaticShiOpts)
	{}

	PCWSTR ModuleName() override
	{
		return L"Shellinst";
	}

	virtual SDE_OPTS &ModuleOptions() override
	{
		return ModOpts;
	}

	static void free_HKEY(HKEY Key)
	{
		RegCloseKey(Key);
	}

	virtual void OpenResources(Module::OPEN_STATUS &OpenStatus, SDE_GENERIC_OPTS const &GOpts, Module::ModuleResourceDest &Res, UCHAR Privileges, BOOLEAN ObjectWanted) override
	{
		PCWSTR KeynameAfso =	L"SOFTWARE\\Classes\\AllFilesystemObjects";
		PCWSTR KeynameShell =	L"SOFTWARE\\Classes\\AllFilesystemObjects\\shell";
		PCWSTR Keyname1t =		L"SOFTWARE\\Classes\\AllFilesystemObjects\\shell\\%s";
		PCWSTR Keyname2t =		L"SOFTWARE\\Classes\\AllFilesystemObjects\\shell\\%s\\command";
		PCWSTR OtherValue =		L"extended";

		WCHAR Keyname1[MAX_STRING_CHARS], Keyname2[MAX_STRING_CHARS];

		swprintf_s(Keyname1, Keyname1t, ModOpts.Opts[OiVerbName].String);
		swprintf_s(Keyname2, Keyname2t, ModOpts.Opts[OiVerbName].String);

		HKEY Root = (ModOpts.Opts[OiLocation].Enum->Choice == LocComputer) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

		if(ModOpts.Opts[OiUninstall].Flags & SDE_OPT_SPECIFIED)
		{
			OpText Ot(L"Uninstalling shell handler");
			{
				OpText Ot2(NULL, Keyname2);
				RaiseOnWin32Error(RegDeleteKey(Root, Keyname2), FALSE);
				Ot2;
			}
			{
				OpText Ot2(NULL, Keyname1);
				RaiseOnWin32Error(RegDeleteKey(Root, Keyname1), FALSE);
				Ot2;
			}
			Ot;
		}

		if(ModOpts.Opts[OiInstall].Flags & SDE_OPT_SPECIFIED)
		{
			OpText Ot(L"Installing shell handler");
			auto_free<HKEY__, &free_HKEY> KeyAfso, KeyShell, Key1, Key2;
			{
				OpText Ot2(NULL, KeynameShell);
				RaiseOnWin32Error(RegCreateKey(Root, KeynameAfso, KeyAfso.assign_indirect()), FALSE);
				Ot2;
			}
			{
				OpText Ot2(NULL, KeynameShell);
				RaiseOnWin32Error(RegCreateKey(Root, KeynameShell, KeyShell.assign_indirect()), FALSE);
				Ot2;
			}
			{
				OpText Ot2(NULL, Keyname1);
				RaiseOnWin32Error(RegCreateKey(Root, Keyname1, Key1.assign_indirect()), FALSE);
				Ot2;
			}
			{
				OpText Ot2(NULL, Keyname2);
				RaiseOnWin32Error(RegCreateKey(Root, Keyname2, Key2.assign_indirect()), FALSE);

				WCHAR ModulePath[MAX_STRING_CHARS];
				WCHAR CommandLine[MAX_STRING_CHARS];

				GetModuleFileName(NULL, ModulePath, MAX_STRING_CHARS);

				swprintf_s(CommandLine, L"\"%s\" t file tc win32 n \"%%1\"", ModulePath);

				RaiseOnWin32Error(RegSetValue(Key2, NULL, REG_SZ, CommandLine, narrowing_cast<DWORD>(wcslen(CommandLine))));
				RaiseOnWin32Error(RegSetValueEx(Key2, OtherValue, 0, REG_SZ, NULL, 0));

				Ot2;
			}
			Ot;
		}

		if(ObjectWanted)
			OpenStatus |= Module::OBJECT_UNKNOWN_TYPE;
	}
};

}//namespace Shellinst